home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / circuits / irsim_ta.z / irsim_ta / irsim / src / ana11 / postscript.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-09-13  |  15.4 KB  |  619 lines

  1. /*
  2.  *     ********************************************************************* 
  3.  *     * Copyright (C) 1988, 1990 Stanford University.                     * 
  4.  *     * Permission to use, copy, modify, and distribute this              * 
  5.  *     * software and its documentation for any purpose and without        * 
  6.  *     * fee is hereby granted, provided that the above copyright          * 
  7.  *     * notice appear in all copies.  Stanford University                 * 
  8.  *     * makes no representations about the suitability of this            * 
  9.  *     * software for any purpose.  It is provided "as is" without         * 
  10.  *     * express or implied warranty.  Export of this software outside     * 
  11.  *     * of the United States of America may require an export license.    * 
  12.  *     *********************************************************************
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include <sys/types.h>
  17. #include <time.h>
  18. #include "ana.h"
  19. #include "ana_glob.h"
  20.  
  21.  
  22. #define    DATE_LEN    25    /* length of ascii date returned by ctime */
  23.  
  24.  
  25. private int    psBanner = TRUE;
  26. private int    psLegend = FALSE;
  27. private int    psTimes = TRUE;
  28. private int    psOutline = TRUE;
  29.  
  30.  
  31. private    void   WritePSfile(), DrawOutline(), PrintNames(), PrintTraces();
  32. private    void   PrintSignal(), PrintVector(), PrintTimes(), PrintLegend();
  33.  
  34.  
  35. public void SetPSParms( s )
  36.   char  *s;
  37.   {
  38.     int  *parm;
  39.  
  40.     switch( s[1] )
  41.       {
  42.     case 'b' :
  43.         psBanner ^= TRUE;
  44.         break;
  45.     case 'l' :
  46.         psLegend ^= TRUE;
  47.         break;
  48.     case 't' :
  49.         psTimes ^= TRUE;
  50.         break;
  51.     case 'o' :
  52.         psOutline ^= TRUE;
  53.         break;
  54.       }
  55.     if( *s == MENU_UNMARK )
  56.     *s = MENU_MARK;
  57.     else
  58.     *s = MENU_UNMARK;
  59.   }
  60.  
  61.  
  62. typedef enum { black, white, gray, xpat } pattern;
  63. private    char      fname[256] = "";
  64. private    FILE      *psout;
  65. private    pattern   currPat;
  66.  
  67.  
  68. public void printPS( s )
  69.   char *s;
  70.   {
  71.     if( traces.disp == 0 or tims.first >= tims.last )
  72.       {
  73.     PRINT( "\nThere's nothing to print" );
  74.     XBell( display, 0 );
  75.     return;
  76.       }
  77.     if( *fname == '\0' )
  78.       {
  79.     strncpy( fname, banner, bannerLen );
  80.     fname[bannerLen] = '\0';
  81.     strcat( fname, ".ps" );
  82.       }
  83.     PRINTF( "\nEnter filename (%s)", fname );
  84.     Query( " > ", WritePSfile );
  85.   }
  86.  
  87.  
  88. private void WritePSfile( psfname )
  89.   char  *psfname;
  90.   {
  91.     char    *date;
  92.     time_t  theTime;
  93.  
  94.     if( psfname == NULL )
  95.     return;
  96.  
  97.     if( *psfname == '\0' )
  98.     psfname = fname;
  99.     else
  100.     strcpy( fname, psfname );
  101.  
  102.     if( (psout = fopen( psfname, "w" )) == NULL )
  103.       {
  104.     PRINTF( "\ncan't open '%s' for output", psfname );
  105.     return;
  106.       }
  107.     PRINTF( "\nWriting %s...", psfname );
  108.     XDefineCursor( display, window, cursors.timer );
  109.     XFlush( display );
  110.  
  111.     currPat = black;
  112.     WritePreamble();
  113.     theTime = time( 0 );
  114.     date = ctime( &theTime );
  115.  
  116.     fprintf( psout, "MSAVE\n" );
  117.     DrawOutline( date );
  118.     if( psTimes )
  119.     PrintTimes( tims.start, tims.end );
  120.     PrintNames();
  121.     PrintTraces( tims.start, min( tims.end, tims.last ) );
  122.     fprintf( psout, "showpage MRESTORE\n" );
  123.  
  124.     if( psLegend )
  125.       {
  126.     DrawOutline( date );
  127.     PrintLegend();
  128.     fprintf( psout, "showpage\n" );
  129.       }
  130.     fclose( psout );
  131.     PRINT( "done" );
  132.     XDefineCursor( display, window, cursors.deflt );
  133.   }
  134.  
  135.  
  136.     /* Macros to Convert from screen to PostScript units */
  137.  
  138. #define    PS_UNITS    72            /* PostScript unit (1/inch) */
  139. #define    ps_YSIZE    (15 * PS_UNITS / 2)    /* y page size = 7.5 inch */
  140. #define    ps_XSIZE    (10 * PS_UNITS)        /* x page size = 10 inch */
  141. #define    XMARGIN        (PS_UNITS / 2)        /* margins 1/2 inch */
  142. #define    YMARGIN        (PS_UNITS / 2)
  143. #define    FSIZE        9            /* default font size */
  144. #define    MINFSIZE    4            /* minimum font size */
  145. #define    LEGFSIZE    7            /* legend font size */
  146.  
  147. #define    YTRACE        (traceBox.bot - traceBox.top + 1)
  148. #define    TIMES_HEIGHT    20
  149. #define    BANNER_HEIGHT    15
  150. #define    psHEIGHT    ( ps_YSIZE - TIMES_HEIGHT - BANNER_HEIGHT )
  151.  
  152.         /* scale conversion macros */
  153. #define    PSX( x )    ( (x) * (ps_XSIZE - 2) / traceBox.right )
  154. #define    PSY( y )    ( (YWINDOWSIZE - (y)) * psHEIGHT / YTRACE )
  155. #define    PS( x, y )    PSX( x ), PSY( y )
  156.  
  157. #define    BANNER_BOT    ( psHEIGHT + PSY( traceBox.bot ) )
  158. #define BANNER_TOP    ( BANNER_BOT + BANNER_HEIGHT )
  159. #define BANNER_MID    ( (BANNER_TOP + BANNER_BOT + 1) / 2 )
  160.  
  161. #define    TIMES_TOP    PSY( traceBox.bot )
  162. #define    TIMES_BOT    (TIMES_TOP - TIMES_HEIGHT )
  163.  
  164.  
  165. /**************************************************************************/
  166. /*    Redefine the graphics operators to generate the PostScript code   */
  167. /**************************************************************************/
  168.  
  169. #define    BLACK        1        /* anything will do */
  170. #define    WHITE        0
  171.  
  172. #define    VLine( X, BOT, TOP, COLOR )                    \
  173.     fprintf( psout, "%d %d %d VL\n", PS( X, BOT), PSY( TOP ) );
  174.  
  175. #define    HLine( LEFT, RIGHT, Y, COLOR )                    \
  176.     fprintf( psout, "%d %d %d HL\n", PS( LEFT, Y ), PSX( RIGHT ) );
  177.  
  178. #define    Line( X1, Y1, X2, Y2 )                        \
  179.     fprintf( psout, "%d %d %d %d L\n", PS( X1, Y1 ), PS( X2, Y2 ) );
  180.  
  181. #define FillAREA( X, Y, WIDTH, HEIGHT, COLOR )                \
  182.   {                                    \
  183.     pattern  opatt = SetPattern( COLOR );                \
  184.     fprintf( psout, "%d %d %d %d BOX fill\n", PS( X, Y ),        \
  185.       PS( (X) + (WIDTH) - 1, (Y) + (HEIGHT) - 1 ) );            \
  186.     (void) SetPattern( opatt );                        \
  187.   }                                    \
  188.  
  189. #define RECT( X, Y, X2, Y2, OP )                    \
  190.     fprintf( psout, "%d %d %d %d BOX %s\n", X, Y, X2, Y2, "OP" );
  191.  
  192. #define StrLeft( S, LEN, LEFT, BOT, FG, BG )                \
  193.   {                                    \
  194.     psString( S, LEN );                            \
  195.     fprintf( psout, "%d %d SL\n", PS( LEFT, BOT ) );            \
  196.   }                                    \
  197.  
  198.  
  199. #define StrRight( S, LEN, RIGHT, MID, FG, BG )                \
  200.   {                                    \
  201.     psString( S, LEN );                            \
  202.     fprintf( psout, "%d %d SR\n", PS( RIGHT, MID ) );            \
  203.   }                                    \
  204.  
  205.  
  206. #define StrCenter( S, LEN, LEFT, RIGHT, MID, FG, BG )            \
  207.   {                                    \
  208.     psString( S, LEN );                            \
  209.     fprintf( psout, "%d %d %d SC\n", PSX( LEFT ), PS( RIGHT, MID ) );    \
  210.   }                                    \
  211.  
  212.  
  213. /**************************************************************************/
  214.  
  215. /*
  216.  * Write out an string, prepending parens with '\'
  217.  */
  218. private void psString( s, len )
  219.   char  *s;
  220.   int   len;
  221.   {
  222.     putc( '(', psout );
  223.     while( *s != '\0' and len != 0 )
  224.       {
  225.     if( (*s == '(' ) || (*s == ')') )
  226.         putc( '\\', psout );
  227.         putc( *s, psout );
  228.     s++;
  229.     len--;
  230.       }
  231.     putc( ')', psout );
  232.   }
  233.  
  234.  
  235. private pattern SetPattern( patt )
  236.   pattern  patt;
  237.   {
  238.     float    grayscale;
  239.     pattern  ret;
  240.  
  241.     if( patt == white )
  242.     grayscale = 1.0;
  243.     else if( patt == gray )
  244.     grayscale = 0.82;
  245.     else if( patt == xpat )
  246.     grayscale = 0.68;
  247.     else /* black */
  248.     grayscale = 0.0;
  249.     fprintf( psout, "%g setgray\n", grayscale );
  250.     ret = currPat;
  251.     currPat = patt;
  252.     return( ret );
  253.   }
  254.  
  255.  
  256. private void DrawOutline( date )
  257.   char  *date;
  258.   {
  259.     pattern  opatt;
  260.     char     info[ 256 ];
  261.  
  262.     if( psBanner )
  263.       {
  264.     opatt = SetPattern( gray );
  265.     RECT( 0, BANNER_BOT, ps_XSIZE, BANNER_TOP, fill );
  266.     (void) SetPattern( opatt );
  267.     RECT( 0, BANNER_BOT, ps_XSIZE, BANNER_TOP, stroke );
  268.     psString( banner, bannerLen );
  269.     fprintf( psout, "%d %d FSIZE 2 div sub SL\n", 6, BANNER_MID );
  270.     if( strncmp( banner, fname, bannerLen ) != 0 )
  271.       {
  272.         sprintf( info, "(%s)  %s", fname, date );
  273.         psString( info, bannerLen + DATE_LEN );
  274.       }
  275.     else
  276.         psString( date, DATE_LEN );
  277.     fprintf( psout, " %d %d SR\n", PSX( traceBox.right - 4 ), BANNER_MID);
  278.       }
  279.     if( psOutline )
  280.     RECT( 0, TIMES_BOT, ps_XSIZE, BANNER_TOP, stroke )
  281.   }
  282.  
  283.  
  284.  
  285.     /* FactorTbl: time grid at multiples of 1/FactorTbl => .1 .5 .25 1 */
  286. private    int    FactorTbl[] = { 10, 2, 4, 1};
  287.  
  288. private void PrintTimes( t1, t2 )
  289.   TimeType t1, t2;
  290.   {
  291.     TimeType  step, half_step, i;
  292.     int       x;
  293.     char      s[ 25 ];
  294.  
  295.     for( step = tims.steps, i = 1; step >= 10; step /= 10, i *= 10 );
  296.     for( x = 0; ; x++ )
  297.       {
  298.     int nsteps = tims.steps /( i / FactorTbl[x] );
  299.     if( nsteps > 5 and nsteps < 15 )
  300.         break;
  301.       }
  302.     step = i / FactorTbl[x];
  303.     half_step = ( step > 2 ) ? (step / 2) - 1 : 2;
  304.  
  305.     fprintf( psout, "0 setlinewidth [1 3] 0 setdash /svfnt currentfont def\n");
  306.     fprintf( psout, "theFont 0.7 FSIZE mul scalefont setfont\n" );
  307.     psString( "time (ns)", 30 );
  308.     fprintf( psout, " %d %d %d SC\n", 0, PSX(traceBox.left) - 1, TIMES_TOP );
  309.  
  310.     i = ((t1 + step - 1) / step) * step;
  311.     if( i != t1 )
  312.       {
  313.     x = TimeToX( t1 );
  314.     VLine( x, traceBox.top, traceBox.bot + 3, BLACK );
  315.     if( i - t1 >= half_step )
  316.       {
  317.         sprintf( s, "%.1f", d2ns( t1 ) );
  318.         x = 2 * PSX( x );
  319.         fprintf( psout, "(%s) 0 %d %d SC\n", s, x, (TIMES_BOT+TIMES_TOP)/2 );
  320.       }
  321.       }
  322.  
  323.     while( i <= t2 )
  324.       {
  325.     x = TimeToX( i );
  326.     VLine( x, traceBox.top, traceBox.bot + 3, BLACK );
  327.     sprintf( s, "%.1f", d2ns( i ) );
  328.     x = 2 * PSX( x );
  329.     fprintf( psout, "(%s) 0 %d %d SC\n", s, x, (TIMES_BOT+TIMES_TOP)/2 );
  330.     i += step;
  331.       }
  332.  
  333.     if( i > t2 and (t2 - i + step) >= half_step )
  334.       {
  335.     x = TimeToX( t2 );
  336.     VLine( x, traceBox.top, traceBox.bot + 3, BLACK );
  337.     sprintf( s, "%.1f", d2ns( t2 ) );
  338.     x = PSX( x );
  339.     fprintf( psout, "(%s) %d %d SR\n", s, x, (TIMES_BOT+TIMES_TOP)/2 );
  340.       }
  341.  
  342.     HLine( traceBox.left - 2, traceBox.right, traceBox.bot, BLACK );
  343.     fprintf( psout, "0.6 setlinewidth [] 0 setdash svfnt setfont\n" );
  344.   }
  345.  
  346.  
  347. private void PrintNames()
  348.   {
  349.     Coord         x, y;
  350.     TraceEnt      *t;
  351.     int           i;
  352.  
  353.     x = namesBox.right - 2;
  354.     for( t = traces.first, i = traces.disp; i != 0; i--, t = t->next )
  355.       {
  356.     y = (t->bot + t->top) / 2;
  357.     StrRight( t->name, t->len, x, y, BLACK, WHITE );
  358.       }
  359.   }
  360.  
  361.  
  362. private void PrintTraces( t1, t2 )
  363.   TimeType  t1,t2;
  364.   {
  365.     Trptr  t;
  366.     int    nt;
  367.  
  368.     for( t = traces.first, nt = traces.disp; nt != 0; nt--, t = t->next )
  369.       {
  370.     if( IsVector( t ) )
  371.         PrintVector( t, t1, t2 );
  372.     else
  373.         PrintSignal( t, t1, t2 );
  374.       }
  375.   }
  376.  
  377.  
  378. private void PrintSignal( t, t1, t2 )
  379.   Trptr              t;
  380.   register TimeType  t1, t2;
  381.   {
  382.     register hptr  h;
  383.     register int   val, change;
  384.     int            x1, x2;
  385.  
  386.     if( t1 >= tims.last )
  387.     return;
  388.  
  389.     h = t->cache[0].wind;
  390.  
  391.     x1 = TimeToX( t1 );
  392.     while( t1 < t2 )
  393.       {
  394.     val = h->val;
  395.     while( h->time < t2 and h->val == val )
  396.         NEXTH( h, h );
  397.  
  398.     if( h->time > t2 )
  399.       {
  400.         change = FALSE;
  401.         t1 = t2;
  402.       }
  403.     else
  404.       {
  405.         change = ( h->val != val );
  406.         t1 = h->time;
  407.       }
  408.     x2 = TimeToX( t1 );
  409.     switch( val )
  410.       {
  411.         case LOW :
  412.         HLine( x1, x2, t->bot, WHITE );
  413.         break;
  414.         case HIGH :
  415.         HLine( x1, x2, t->top, WHITE );
  416.         break;
  417.         case X :
  418.         FillAREA( x1, t->top, x2 - x1 + 1, t->bot - t->top + 1, xpat );
  419.         if( x1 > traceBox.left + 1 )
  420.             VLine( x1, t->bot, t->top, WHITE );
  421.         break;
  422.       }
  423.     if( change )
  424.         VLine( x2, t->bot, t->top, WHITE );
  425.     x1 = x2;
  426.       }
  427.   }
  428.  
  429.  
  430. private void PrintVector( t, t1, t2 )
  431.   register Trptr     t;
  432.   register TimeType  t1, t2;
  433.   {
  434.     hptr      *start, *changes;
  435.     TimeType  firstChange;
  436.     int       x1, x2, xx, mid, nbits, strlen;
  437.     
  438.     if( t1 >= tims.last )
  439.     return;
  440.  
  441.     nbits = t->n.vec->nbits;
  442.     start = tmpHBuff;
  443.     changes = &(tmpHBuff[ nbits ]);
  444.     strlen = (nbits + t->bdigit - 1) / t->bdigit;
  445.  
  446.       {
  447.     register hptr      h, *s;
  448.     register int       n, val;
  449.     register hptr      *ch = changes;
  450.     register TimeType  tm = tims.end;
  451.  
  452.     s = start;            /* initialize start array */
  453.     firstChange = tims.start;
  454.     for( n = nbits - 1; n >= 0; n-- )
  455.       {
  456.         h = s[n] = t->cache[n].wind;
  457.         val = h->val;
  458.         while( h->time < tm and h->val == val )
  459.         NEXTH( h, h );
  460.         ch[n] = h;
  461.       }
  462.       }
  463.  
  464.     mid = (t->top + t->bot) / 2;
  465.     x2 = TimeToX( t2 );
  466.     x1 = TimeToX( firstChange );
  467.  
  468.     while( t1 < t2 )
  469.       {
  470.       {                /* find nearest change in time */
  471.         register hptr  *ch;
  472.         register int   n;
  473.  
  474.         t1 = tims.end + 1;
  475.         for( ch = changes, n = nbits - 1; n >= 0; n-- )
  476.           {
  477.         if( ch[n]->time < t1 )
  478.             t1 = ch[n]->time;
  479.           }
  480.       }
  481.  
  482.     if( t1 <= t2 )            /* change before t2 => draw it */
  483.       {
  484.         x2 = TimeToX( t1 );
  485.         if( x2 - x1 > 3 )
  486.           {
  487.         HLine( x1 + 2, x2 - 2, t->top, WHITE );
  488.         HLine( x1 + 2, x2 - 2, t->bot, WHITE );
  489.         xx = 2;
  490.           }
  491.         else
  492.         xx = (x2 - x1 - 2);
  493.  
  494.         VLine( x2, t->bot - 2, t->top + 2, WHITE );
  495.         if( x2 > traceBox.left + 1 )
  496.           {
  497.         Line( x2 - xx, t->top, x2, t->top + 2 );
  498.         Line( x2 - xx, t->bot, x2, t->bot - 2 );
  499.           }
  500.         if( x2 < traceBox.right - 1 )
  501.           {
  502.         Line( x2, t->top + 2, x2 + 2, t->top );
  503.         Line( x2, t->bot - 2, x2 + 2, t->bot );
  504.           }
  505.       }
  506.     else                /* change after t2 */
  507.       {
  508.         register TimeType  tm;
  509.  
  510.         tm = min( t1, min( tims.end, tims.last ) );
  511.         x2 = TimeToX( tm );
  512.         HLine( x1 + 2, x2, t->top, WHITE );
  513.         HLine( x1 + 2, x2, t->bot, WHITE );
  514.       }
  515.  
  516.      {
  517.         char  *str;
  518.         str = HistToStr( start, nbits, t->bdigit, 1 );
  519.         StrCenter( str, strlen, x1, x2, mid, WHITE, BLACK );
  520.       }
  521.  
  522.       {
  523.         register hptr      h;
  524.         register hptr      *ch, *s;
  525.         register int       n, val;
  526.         register TimeType  tm = tims.end;
  527.  
  528.         for( s = start, ch = changes, n = nbits - 1; n >= 0; n-- )
  529.           {
  530.         if( ch[n]->time == t1 )
  531.           {
  532.             h = s[n] = ch[n];
  533.             val = h->val;
  534.             while( h->time < tm and h->val == val )
  535.             NEXTH( h, h );
  536.             ch[n] = h;
  537.           }
  538.           }
  539.       }
  540.     x1 = x2;
  541.       }
  542.   }
  543.  
  544.  
  545. private void PrintLegend()
  546.   {
  547.     int       i, nbits;
  548.     TraceEnt  *t;
  549.  
  550.     fprintf( psout, "/GX %d  def\n", PSX( namesBox.right + 25 ) );
  551.     fprintf( psout, "/GY %d  def\n", BANNER_BOT - 2 * (FSIZE + 3)  );
  552.     fprintf( psout, "(Legend:) 4 %d SL\n", BANNER_BOT - FSIZE - 2 );
  553.     fprintf( psout, "/FSIZE %d def FSIZE SF\n", LEGFSIZE );
  554.  
  555.     for( i = traces.disp, t = traces.first; i != 0; i--, t = t->next )
  556.       {
  557.     if( t->vector )
  558.       {
  559.         for( nbits = t->n.vec->nbits - 1; nbits >= 0; nbits-- )
  560.         psString( t->n.vec->nodes[nbits]->nname, 1000 );
  561.         nbits = t->n.vec->nbits;
  562.       }
  563.     else
  564.       {
  565.         psString( t->n.nd->nname, 1000 );
  566.         nbits = 1;
  567.       }
  568.     psString( t->name, 1000 );
  569.     fprintf( psout, "%d LE\n", nbits );
  570.       }
  571.   }
  572.  
  573.  
  574.  
  575. WritePreamble()
  576.   {
  577.     static char defs[] = "%!\n\
  578. /MSAVE { /mStat save def } def\n\
  579. /MRESTORE { mStat restore } def\n\
  580. /SET { exch def } def\n\
  581. /SF { /wi SET theFont [wi 0 0 FSIZE 0 0] makefont setfont } def\n\
  582. /L { newpath moveto lineto stroke } def\n\
  583. /VL { 2 index exch L } def\n\
  584. /HL { 1 index L } def\n\
  585. /BOX { /@yb SET /@xb SET /@yt SET /@xt SET newpath\n\
  586.  @xb @yb moveto @xb @yt lineto @xt @yt lineto @xt @yb lineto closepath } def\n\
  587. /SL { moveto show } def\n\
  588. /SR { exch dup /@xr SET 2 index stringwidth pop sub dup\n\
  589.  0 le { pop 0 @xr 3 -1 roll SC } { exch FSIZE 2 div sub moveto show }\n\
  590.  ifelse } def\n\
  591. /SCP { /@s SET @s stringwidth pop /@sw SET @sw 2 div sub\n\
  592.  dup @sw add maxX gt { pop maxX @sw sub } if exch moveto @s show } def\n\
  593. /SC { FSIZE 2 div sub /@y SET /@x2 SET /@x1 SET /@s SET\n\
  594.  /@l @x2 @x1 sub def /@x @x1 @x2 add 2 div def\n\
  595.  /@w @s stringwidth pop def @l @w gt\n\
  596.  { @y @x @s SCP }\n\
  597.  { @l FSIZE mul @w 1 add div dup MINFSIZE lt\n\
  598.  { pop } { /svf currentfont def SF @y @x @s SCP svf setfont } ifelse }ifelse\n\
  599. } def\n\
  600. /LE { exch GX GY FSIZE 2 div add SR /@x GX def\n\
  601.  { dup stringwidth pop /@w SET /@x @x FSIZE add def @x @w add\n\
  602.  720 ge { /@x GX FSIZE add def /GY GY FSIZE 2 add sub def } if\n\
  603.  @x GY SL /@x @x @w add def } repeat /GY GY FSIZE 4 add sub def } def\n\
  604. ";
  605.     /* print data and procedure definitions */
  606.     fprintf( psout, "%s", defs );
  607.     fprintf( psout, "/FSIZE %d def /MINFSIZE %d def ", FSIZE, MINFSIZE );
  608.     fprintf( psout, "/maxX %d def\n", PSX( traceBox.right ) );
  609.     /* Switch to landscape mode */
  610.     fprintf( psout, "%d 0 translate\n", 17 * PS_UNITS / 2 );
  611.     fprintf( psout, "90 rotate\n" );
  612.     fprintf( psout, "%d %d", XMARGIN, YMARGIN + TIMES_HEIGHT -
  613.       PSY( traceBox.bot) );
  614.     fprintf( psout, " translate\n" );
  615.     fprintf( psout, "1 setlinecap 0.6 setlinewidth \n" );
  616.     /* Set up text font */
  617.     fprintf( psout,"/theFont /Helvetica findfont def FSIZE SF\n");
  618.   }
  619.